#ifdef DecalLighting
#define DecalMappingExplicit 0
#define DecalMappingPlanar 1
#define DecalMappingSpherical 2
#define DecalMappingCubic 3
#define DecalMappingFiniteCylindrical 4
#define DecalMappingInfiniteCylindrical 5

  //_decalPosition is computed in ShaderBuilderUberPS
  vec3 _decalPosition = vec3(0.0);
  vec3 _decalNormal = vec3(0.0);
  vec2 pmDecalTexCoords = vec2(0.0);
  vec2 pmDecalTexCoordsOffset = vec2(0.0);
  vec3 pmDecalTangent = vec3(0.0);
  vec3 pmDecalBinormal = vec3(0.0);

  vec3 vComputeDecalNormal(vec3 iU, vec3 iV, vec3 iDecalNormal, vec3 iSurfaceNormal)
  {
    vec3 worldUPrime = vNormalize(iU - dot(iU, iSurfaceNormal) * iSurfaceNormal);
    vec3 worldVPrime = vNormalize(iV - dot(iV, iSurfaceNormal) * iSurfaceNormal);

    return vNormalize(
        iDecalNormal.x*worldUPrime
      + iDecalNormal.y*worldVPrime
      + iDecalNormal.z*iSurfaceNormal);  
  }

  vec2 vGetUvs()
  {
  #if DecalMappingOperator == DecalMappingExplicit
    #ifdef PhysicalMaterial
      vec2 tc = vec2(mat3(PMat.uvTransformation) * vec3(pmDecalTexCoords, 1.0));
    #else
      vec2 tc = pmDecalTexCoords;
    #endif
  #else
    vec2 tc = pmDecalTexCoords;
  #endif

  #if defined(TextureMatrix)
    tc = (vGetTextureMatrix() * vec4(tc, 0.0, 1.0)).xy;
  #endif

  #if DecalMappingOperator != DecalMappingExplicit
    tc += 0.5;
  #endif

    return tc;
  }
  
#if defined(heightMapEnabled) && defined(FragmentStage)
  vec2 vGetUvOffset()
  {
    return pmDecalTexCoordsOffset;
  }
#endif

  vec3 vGetTangent()
  {
    return pmDecalTangent;
  }

  vec3 vGetBinormal()
  {
    return pmDecalBinormal;
  }

#if (DecalMappingOperator == DecalMappingExplicit)
  void ComputeMapping(in vec3 iPosition, in vec3 iNormal, in vec3 iX, in vec3 iY, in vec3 iZ)
  {

  }
#elif (DecalMappingOperator == DecalMappingPlanar)
  void ComputeMapping(in vec3 iPosition, in vec3 iNormal, in vec3 iX, in vec3 iY, in vec3 iZ)
  {
    float fact = _decalPosition.z >= 0.0 ? 1.0 : -1.0;

    pmDecalTexCoords = _decalPosition.xy;
    pmDecalTangent = iX ;
    pmDecalBinormal = iY;
  }
#elif (DecalMappingOperator == DecalMappingSpherical)
  void ComputeMapping(in vec3 iPosition, in vec3 iNormal, in vec3 iX, in vec3 iY, in vec3 iZ)
  {  
    vec3 pos = _decalPosition;
    float radius3d = max(0.000001,length(_decalPosition.xyz));
    float z_by_radius3d = _decalPosition.z / radius3d;
  
    float theta = atan(_decalPosition.y, _decalPosition.x);
    float phi   = asin(z_by_radius3d );

    pmDecalTexCoords = vec2(theta, phi) * vec2(radius3d);
    float cos_theta = cos(theta), sin_theta = sin(theta), cos_phi = cos(phi), sin_phi = z_by_radius3d;
    pmDecalTangent  = -sin_theta*iX + cos_theta*iY;
    pmDecalBinormal = -cos_theta*sin_phi*iX - sin_theta*sin_phi*iY + cos_phi*iZ;
  }
#elif (DecalMappingOperator == DecalMappingCubic)
  void ComputeMapping(in vec3 iPosition, in vec3 iNormal, in vec3 iX, in vec3 iY, in vec3 iZ)
  {  
    vec3 pos = _decalPosition;
    vec3 absolute_normal = abs(_decalNormal);  
    float maxima_normal = max(absolute_normal.x, max(absolute_normal.y, absolute_normal.z));
    vec3 _sign;
  
    _sign.x = _decalPosition.x >= 0.0 ? 1.0 : -1.0;
    _sign.y = _decalPosition.y >= 0.0 ? -1.0 : 1.0;
    _sign.z = _decalPosition.z >= 0.0 ? 1.0 : -1.0;

    if(maxima_normal == absolute_normal.x)
    {
      pmDecalTexCoords = vec2(_sign.x * pos.y, pos.z );
      pmDecalTangent = iY;
      pmDecalBinormal = iZ;
    }
    else if(maxima_normal == absolute_normal.y)
    {
      pmDecalTexCoords = vec2(_sign.y * pos.x, pos.z );
      pmDecalTangent = iX;
      pmDecalBinormal = iZ;
    }
    else
    {
      pmDecalTexCoords = vec2(_sign.z * pos.x, pos.y);
      pmDecalTangent = iX;
      pmDecalBinormal = iY;
    }

  }
#elif (DecalMappingOperator == DecalMappingFiniteCylindrical)
  void ComputeMapping(in vec3 iPosition, in vec3 iNormal, in vec3 iX, in vec3 iY, in vec3 iZ)
  {  
    vec3 pos = _decalPosition;
    vec3 absolute_normal = abs(_decalNormal);    
    float maxima_normal = max(absolute_normal.x, max(absolute_normal.y, absolute_normal.z));

    if(maxima_normal == absolute_normal.z)
    {
      float signPosZ = vSignf(_decalPosition.z);
      pmDecalTexCoords = vec2(signPosZ*pos.x, pos.y);        
      pmDecalTangent = iX;
      pmDecalBinormal = iY;
    }
    else
    {
      float radius2d = length(_decalPosition.xy);
      float radius3d = length(_decalPosition.xyz);
      float z_by_radius3d = _decalPosition.z/radius3d;
      float theta = atan(_decalPosition.y, _decalPosition.x);
      float phi = asin(z_by_radius3d);
      pmDecalTexCoords = vec2(theta, _decalPosition.z) * vec2(radius2d, 1.0);    
      float cos_theta = cos(theta), sin_theta = sin(theta);
      pmDecalTangent = -sin_theta*iX + cos_theta*iY;
      pmDecalBinormal = iZ;   
    }
  }
#elif (DecalMappingOperator == DecalMappingInfiniteCylindrical)
  void ComputeMapping(in vec3 iPosition, in vec3 iNormal, in vec3 iX, in vec3 iY, in vec3 iZ)
  {  
    float radius2d = length(_decalPosition.xy);
    float radius3d = max(0.000001,length(_decalPosition.xyz));
    float z_by_radius3d = _decalPosition.z/radius3d;

    float theta = atan(_decalPosition.y, _decalPosition.x);
    float phi   = asin(z_by_radius3d);

    pmDecalTexCoords = vec2(theta, _decalPosition.z) * vec2(radius2d, 1.0);
    float cos_theta = cos(theta), sin_theta = sin(theta);
    pmDecalTangent = -sin_theta*iX + cos_theta*iY;
    pmDecalBinormal = iZ;
  }
#endif
  void TransformUv()
  {    
  }
#endif
